package influence.propagation.implementation;

import influence.propagation.core.Model;
import influence.propagation.core.ModelBuilder;
import influence.propagation.core.Parser;
import influence.propagation.exception.IllegalArgumentException;
import influence.propagation.exception.InputFormatException;

import java.io.File;
import java.io.FileNotFoundException;

import org.neo4j.cypher.javacompat.ExecutionEngine;
import org.neo4j.graphdb.GraphDatabaseService;
import org.neo4j.graphdb.Transaction;

/**
 * La classe Model factory permette la creazione dei modelli in base
 * all'algoritmo scelto
 * 
 * @author Valerio
 *
 */
public class ModelFactory {

	private ModelFactory() {
	}

	/**
	 * ReStituisce il modello per l'algoritmo Indipendent Cascade
	 * 
	 * @param db
	 *            il database di utilizzo
	 * @param graph
	 *            il file .graph contenente il database della forma
	 *            "<"nodo_sorgente,nodo_destinazione,peso_dell_arco">"
	 * @param activeNode
	 *            il file contenente i nodi iniziali attivi
	 * @return il modello
	 * @throws FileNotFoundException
	 * @throws IllegalArgumentException
	 * @throws InputFormatException
	 */
	public static Model createNewIndependentCascadeModel(
			GraphDatabaseService db, File graph, File activeNode)
			throws FileNotFoundException, IllegalArgumentException,
			InputFormatException {
		eraseDatabase(db);// elimino qualsiasi cosa nel database
		if (!graph.getName().endsWith(".graph")) {
			throw new IllegalArgumentException("Il file non e' un .ghraph");
		}
		Parser parser = new DefaultGraphParser(graph);
		Parser parserAN = new DefaultActivityNodeParser(activeNode);
		ModelBuilder builder = new IndependentCascadeModelBuilder(db);
		Transaction transaction = null;//alias
		parser.open();
		parserAN.open();
		boolean buildOne = false;
		try (Transaction tx = db.beginTx()) {
			transaction = tx;
			while (parser.hasMoreToken()) {
				String token = parser.getNextToken();
				builder.create(token);
				buildOne = true;
			}
			while (parserAN.hasMoreToken()) {
				String token = parserAN.getNextToken();
				builder.createActiveNode(token);
			}
			transaction.success();
		} catch (Exception e) {
			if(buildOne){
				transaction.failure();
			}
			throw e;
		} finally {
			parser.close();
			parserAN.close();
		}
		return builder.getInstance();
	}

	private static void eraseDatabase(GraphDatabaseService db) {
		ExecutionEngine executor = new ExecutionEngine(db);
		executor.execute("match ()-[r]-() delete r");
		executor.execute("match (n) delete n");
	}
}
